#
# This file is a part of the open-eBackup project.
# This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
# If a copy of the MPL was not distributed with this file, You can obtain one at
# http://mozilla.org/MPL/2.0/.
#
# Copyright (c) [2024] Huawei Technologies Co.,Ltd.
#
# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
# EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
# MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
#

import functools

from common.const import ExecuteResultEnum, SubJobStatusEnum, DBLogLevel
from common.exception.common_exception import ErrCodeException
from common.util.common_utils import proactively_report_progress
from gaussdbt.single import LOGGER
from gaussdbt.single.comm.gst_single_const import GstSingleConst
from gaussdbt.single.comm.gst_single_error_code import ErrorCode
from gaussdbt.single.comm.utils.gst_single_comm_utils import GstSingleCommonUtil
from gaussdbt.single.comm.utils.gst_single_param_utils import GstSingleParamUtil


def parse_event_label_param_values(param_names, param_dict):
    """
    解析事件标签参数值列表
    :param param_names: 事件标签参数名称列表
    :param param_dict: 任务参数
    :return: 事件标签参数值列表
    """
    label_param_values = list()
    param_dict = param_dict if isinstance(param_dict, dict) else dict()
    param_func_mappings = {
        GstSingleConst.PARAM_JOB_ID: GstSingleParamUtil.get_job_id,
        GstSingleConst.PARAM_SUB_JOB_ID: GstSingleParamUtil.get_sub_job_id,
        GstSingleConst.PARAM_NODE_IP: GstSingleParamUtil.get_node_ip
    }
    for i in param_names:
        if i in param_func_mappings:
            label_param_values.append(str(param_func_mappings[i](param_dict)))
            continue
        label_param_values.append("")
    return label_param_values


def job_exception_decorator(write_progress=False):
    """
    处理备份任务异常返回结果的装饰器
    @param write_progress: 是否写进度信息，True：写；False：不写
    """
    def decorator(func):
        @functools.wraps(func)
        def inner(*args, **kwargs):
            bak_inst = args[0]
            try:
                return func(*args, **kwargs)
            except Exception as ex:
                err_msg = f"Execute task failed, function name: {func.__name__}."
                LOGGER.exception(err_msg)
                ex = ex if isinstance(ex, ErrCodeException) else ErrCodeException(
                    ErrorCode.OPERATION_FAILED, message=err_msg)
                if write_progress:
                    log_label, p_names = GstSingleConst.FUNC_LABEL_PARAMS_MAP.get(func.__name__, (None, list()))
                    log_info_params = parse_event_label_param_values(p_names, bak_inst.param_dict)
                    job_detail = GstSingleCommonUtil.build_log_detail(
                        log_label, log_info_params, err_code=ex.error_code, log_detail_param=ex.parameter_list,
                        log_level=DBLogLevel.ERROR.value)
                    bak_inst.sub_job_detail.task_status = SubJobStatusEnum.FAILED.value
                    bak_inst.sub_job_detail.log_detail = [job_detail]
                    proactively_report_progress(bak_inst.pid, bak_inst.sub_job_detail, LOGGER)
                return GstSingleCommonUtil.build_action_result(
                    code=ExecuteResultEnum.INTERNAL_ERROR.value, body_err=ex.error_code, message=ex.error_message,
                    err_params=ex.parameter_list)

        return inner

    return decorator
